
package cn.mj.commonutil;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Reader;
import java.io.Writer;
import java.math.BigInteger;
import java.security.MessageDigest;


public final class FileUtil {
	
	private FileUtil() {
	}

	static final String CHECKSUM_FILENAME = "checksum";

	/**
	 * Deletes a file or directory.
	 * 
	 * @param spec
	 *            the directory to delete.
	 * @return true if successful, false otherwise.
	 */
	public static boolean deleteDir(File spec) {
		if (spec.isDirectory()) {
			String[] children = spec.list();
			for (int i = 0; i < children.length; i++) {
				if (!deleteDir(new File(spec, children[i]))) {
					return false;
				}
			}
		}
		return spec.delete();
	}

	/**
	 * Deletes a file or directory.
	 * 
	 * @param path
	 *            the name of the file or dir to delete.
	 * @return true if successful, false otherwise.
	 */
	public static boolean deleteDir(String path) {
		return deleteDir(new File(path));
	}

	/**
	 * Deletes a file or directory.
	 * 
	 * @param spec
	 *            the file or dir to delete.
	 * @return true if successful, false otherwise.
	 */
	public static boolean deleteFile(File spec) {
		return deleteDir(spec);
	}

	/**
	 * Deletes a file or directory.
	 * 
	 * @param path
	 *            the name of the file or dir to delete.
	 * @return true if successful, false otherwise.
	 */
	public static boolean deleteFile(String path) {
		return deleteDir(new File(path));
	}

	/**
	 * Renames a file or directory.
	 * 
	 * @param oldName
	 *            the original name of the file.
	 * @param newName
	 *            the name the file should be renamed to.
	 * @return true if successful, false otherwise.
	 */
	public static boolean rename(String oldName, String newName) {
		File fold = new File(oldName);
		File fnew = new File(newName);
		return fold.renameTo(fnew);
	}

	/**
	 * Copies one file to another, optionally appending.
	 * 
	 * @param from
	 *            the file to be copied.
	 * @param to
	 *            the destination file.
	 * @return true if successful, false otherwise.
	 */
	public static boolean copyFile(File from, File to, boolean append) {
		boolean ok = true;
		try {
			BufferedInputStream in = new BufferedInputStream(
					new FileInputStream(from), 64 * 1024);
			BufferedOutputStream out = new BufferedOutputStream(
					new FileOutputStream(to, append), 64 * 1024);
			byte[] buf = new byte[8 * 1024];
			int len = 0;
			while ((len = in.read(buf)) != -1) {
				out.write(buf, 0, len);
			}
			in.close();
			out.close();
		} catch (IOException e) {
			e.printStackTrace();
			ok = false;
		}
		return ok;
	}

	/**
	 * Copies one file to another, overwriting the destination file.
	 * 
	 * @param from
	 *            the file to be copied.
	 * @param to
	 *            the destination file.
	 * @return true if successful, false otherwise.
	 */
	public static boolean copyFile(File from, File to) {
		return copyFile(from, to, false);
	}

	/**
	 * Copies one file to another
	 * 
	 * @param from
	 *            the name of the file to be copied.
	 * @param to
	 *            the name of the destination file.
	 * @return true if successful, false otherwise.
	 */
	public static boolean copyFile(String from, String to) {
		return copyFile(new File(from), new File(to));
	}

	/**
	 * Gets the size of a file or directory, in bytes. This method is needed
	 * because the File.length() method is not defined for directories.
	 * 
	 * @param spec
	 *            the file or directory whose size is requested.
	 * @return the size of the file or directory.
	 */
	public static long sizeOf(File spec) {
		long size = 0;
		if (spec.isDirectory()) {
			String[] children = spec.list();
			for (int i = 0; i < children.length; i++) {
				size += sizeOf(new File(spec, children[i]));
			}
		} else {
			size = spec.length();
		}
		return size;
	}

	

	/**
	 * Returns the absolute path of the given directory.
	 * 
	 * @throws java.io.IOException
	 * @todo see the method's body
	 */
	public static String getDir(String path) throws IOException {
		File f = null;
		if (path.startsWith(Character.toString(File.separatorChar))) {
			f = new File(path);
		} else {// XXX TODO: is this necessary?
			f = new File(".", path);
		}
		return f.getCanonicalPath();
	}

	public static File createTempDir(final String prefix, final String suffix)
			throws IOException {
		File retVal = null;
		java.util.Random random = new java.util.Random(
				System.currentTimeMillis());
		int retry = 0;
		while ((null == retVal) && retry < 20) {
			retVal = new File(System.getProperty("java.io.tmpdir")
					+ File.separator + prefix + random.nextInt() + suffix);
			if (!retVal.mkdir()) {
				retVal = null;
				retry++;
			}
		}
		if (null == retVal) {
			throw new IOException("Can't create a temporary directory in "
					+ System.getProperty("java.io.tmpdir"));
		}
		retVal.deleteOnExit();
		return retVal;
	}

	public static File createOrGetDir(String path, boolean mustBeReadable,
			boolean mustBeWritable) throws IOException {
		File dir = new File(path);
		createIfDoesntExist(dir, mustBeReadable, mustBeWritable);
		return dir;
	}

	/**
	 * creates a directory if it doesnt exist and verifies permissions
	 * 
	 * @param dir
	 * @param mustBeReadable
	 * @param mustBeWritable
	 * @throws IOException
	 */
	public static void createIfDoesntExist(File dir, boolean mustBeReadable,
			boolean mustBeWritable) throws IOException {
		if (dir.exists()) {
			if (!dir.isDirectory())
				throw new IOException(dir.getAbsolutePath()
						+ " exists but isn't a directory");
		} else {
			if (!dir.mkdirs())
				throw new IOException("Couldn't create directory "
						+ dir.getAbsolutePath());
		}

		if (mustBeReadable && !dir.canRead())
			throw new IOException("Cannot read from " + dir.getAbsolutePath());
		if (mustBeWritable && !dir.canWrite())
			throw new IOException("Cannot write in " + dir.getAbsolutePath());
	}

	/**
	 * gets a file that exists and matches the requested permissions or throws
	 * an exception checks if it s a file or a directory
	 * 
	 * @param path
	 *            the file path
	 * @param mustBeReadable
	 *            whether to check for reading permission
	 * @param mustBeWritable
	 *            whether to check for writing permission
	 * @param isDirectory
	 *            true if it should be a directory, false if a file
	 * @return a File representing that file
	 */
	public static File getExistingFile(String path, boolean mustBeReadable,
			boolean mustBeWritable, boolean isDirectory) throws IOException {
		File file = getExistingFile(path, mustBeReadable, mustBeWritable);
		if (file.isDirectory() && !isDirectory)
			throw new IOException(file.getAbsolutePath()
					+ " exists but is not a file");
		if (!file.isDirectory() && isDirectory)
			throw new IOException(file.getAbsolutePath()
					+ " exists but is not a directory");
		return file;
	}

	/**
	 * gets a file that exists and matches the requested permissions or throws
	 * an exception (can be a file or a directory)
	 * 
	 * @param path
	 *            the file path
	 * @param mustBeReadable
	 *            whether to check for reading permission
	 * @param mustBeWritable
	 *            whether to check for writing permission
	 * @return a File representing that file
	 */
	public static File getExistingFile(String path, boolean mustBeReadable,
			boolean mustBeWritable) throws IOException {
		File file = new File(path);
		if (!file.exists())
			throw new FileNotFoundException("file not found: "
					+ file.getAbsolutePath());
		if (mustBeReadable && !file.canRead())
			throw new IOException("Cannot read from " + file.getAbsolutePath());
		if (mustBeWritable && !file.canWrite())
			throw new IOException("Cannot write in " + file.getAbsolutePath());
		return file;
	}

	/**
	 * Gets the absolute path of a file with given filename, searching
	 * classpath.
	 * 
	 * Useful to use log4j's PropertyConfigurator even if log4j.properties is
	 * not placed in the working directory of the jvm.
	 * 
	 * @param filename
	 *            The name of the file that has to be searched in the classpath
	 * @return the absolute path of the file if found, or null otherwise.
	 */
	public static String getFilePathFromClasspath(String filename) {

		java.net.URL url = ClassLoader.getSystemClassLoader().getResource(
				filename);
		if (null != url && "file".equals(url.getProtocol())) {
			return url.getPath();
		}

		// resource not found as "file://"
		return null;

	}

	/**
	 * writes a file with the given content. If content == null or "" it writes
	 * an empty file
	 * 
	 * @param file
	 * @param content
	 * @throws IOException
	 */
	public static void writeFile(File file, String content) throws IOException {
		Writer w = new FileWriter(file);
		if (content != null)
			w.write(content);
		w.flush();
		w.close();
	}

	/**
	 * reads an entire char based file into a string
	 * 
	 * @param file
	 * @return the contents in a string
	 * @throws IOException
	 */
	public static String readFile(File file) throws IOException {
		return readAll(new FileReader(file));
	}

	public static String readAll(Reader reader) throws IOException {
		BufferedReader br = null;
		try {
			br = new BufferedReader(reader);
			StringBuffer buf = new StringBuffer();
			char[] buffer = new char[256];
			while (true) {
				int charsRead = br.read(buffer);
				if (charsRead == -1)
					break;
				buf.append(buffer, 0, charsRead);
			}
			return buf.toString();
		} finally {
			if (br != null)
				br.close();
		}
	}
	
	
	
	public static String getFileMD5(File file)throws Exception {
		   
	    MessageDigest digest = null;
	    FileInputStream in=null;
	    byte buffer[] = new byte[1024];
	    int len;
	    
	     digest = MessageDigest.getInstance("MD5");
	     in = new FileInputStream(file);
	     while ((len = in.read(buffer, 0, 1024)) != -1) {
	        digest.update(buffer, 0, len);
	     }
	      in.close();
	    
	    BigInteger bigInt = new BigInteger(1, digest.digest());
	    return bigInt.toString(16);
	  }

	
	public static void main(String[] argv) {

	}

}